#!/bin/sh
set -x
RPM_FLAG=0
RESULT_PATH="/tmp/pkg_test"
DEL_ITEM_IN_PACKAGES_LIST=("Available Packages" "Installed Packages")
HELP_CMD_LIST=("--help" "-h" "-help" "help")
COREDUMP_PATH="/home/coredump"
COREDUMP_COUNT=0
BLACKLIST="$TONE_SUITE_DIR/pkg-smoke-test/blacklist"
MAX_LOG_SIZE=10000000
ARCH=$(uname -m)

function ldd_check() {
    local exist_flag bin_name
    exist_flag=0
    bin_name=$1
    ldd $bin_name | grep "not found" && {
        echo "Error: ldd check failed on $bin_name"
        ((exist_flag++))
    }
    return $exist_flag
}

function get_repolist() {
    local version
    version=$(cat /etc/os-release | grep ID= | awk -F'"' '{print $2}' | xargs)
    if echo $version | grep "alinux 2"; then
        yum repolist | grep AliYun | awk '{print $1}' | awk -F '/' '{print $1}' >$RESULT_PATH/repolist.txt
    elif echo $version | grep "alinux 3"; then
        yum repolist | grep alinux3 | awk '{print $1}' >$RESULT_PATH/repolist.txt
    elif echo $version | grep "anolis 7.9"; then
        yum repolist | grep AnolisOS | awk '{print $1}' | awk -F '/' '{print $1}' >$RESULT_PATH/repolist.txt
    elif echo $version | grep "anolis 8"; then
        yum repolist | grep Anolis | awk '{print $1}' >$RESULT_PATH/repolist.txt
    else
        yum repolist | awk '{if (NR>1){print $1}}' >$RESULT_PATH/repolist.txt
    fi
    while read -u 7 line; do
        exec_by_repo $line check_coredump
    done 7<$RESULT_PATH/repolist.txt

}
function set_coredump() {
    mkdir -p $COREDUMP_PATH
    COREDUMP_COUNT=$(ls $COREDUMP_PATH | wc -l)
    cp -a /proc/sys/kernel/core_pattern /tmp
    pre_ulimit=$(ulimit -c)
    if [ $pre_ulimit != "unlimited" ]; then
        ulimit -c unlimited
    fi

    echo $COREDUMP_PATH/core-%e-%p >/proc/sys/kernel/core_pattern
    cp -a /etc/systemd/system.conf /tmp
    sed -i s/.*DefaultLimitCORE=.*/DefaultLimitCORE=infinity/ /etc/systemd/system.conf
    systemctl daemon-reload
    systemctl daemon-reexec
    sleep 1 # wait daemono-reexec
}

function clean_coredump() {
    cat /tmp/core_pattern >/proc/sys/kernel/core_pattern
    mv /tmp/system.conf /etc/systemd/system.conf
    ulimit -c $pre_ulimit
    systemctl daemon-reload
    systemctl daemon-reexec
    rm -rf /tmp/core_pattern
    rm -rf $COREDUMP_PATH
}

function check_coredump() {
    local core_dump_cnt
    core_dump_cnt=$(ls $COREDUMP_PATH | wc -l)
    if [ $core_dump_cnt -gt $COREDUMP_COUNT ]; then
        COREDUMP_COUNT=$core_dump_cnt
        return 1
    fi
    COREDUMP_COUNT=$core_dump_cnt
    return 0
}

function check_pkg_inst() {
    local pkg_name
    pkg_name=$1
    rpm -ql $pkg_name >&/dev/null || RPM_FLAG=1
}

function inst_pkg() {
    local pkg_name install_log
    pkg_name=$1
    install_log="$RESULT_PATH/${pkg_name}_install.log"
    if [ $RPM_FLAG == 1 ]; then
        if yum install -y $pkg_name >&$install_log; then
            rm -rf $install_log
            return 0
        fi
        RPM_FLAG=0
        return 1
    fi
    return 0
}

function uninst_pkg() {
    local pkg_name uninstall_log
    pkg_name=$1
    uninstall_log="$RESULT_PATH/${pkg_name}_uninstall.log"
    if [ $RPM_FLAG == 1 ]; then
        # can not use "yum remove", it will remove deps too.
        if rpm -e --nodeps $pkg_name >&$uninstall_log; then
            rm -rf $uninstall_log
            return 0
        fi
        return 1
    fi
    return 0
}

function delete_unuse_item() {
    file=$1
    for ((i = 0; i < ${#DEL_ITEM_IN_PACKAGES_LIST[@]}; i++)); do
        sed -i "/^${DEL_ITEM_IN_PACKAGES_LIST[i]}/d" $file
    done
}

function gen_packages_list() {
    local repo
    repo=$1
    yum repo-pkgs $repo list -q >$RESULT_PATH/$repo.tmp_file
    delete_unuse_item $RESULT_PATH/$repo.tmp_file
    cat $RESULT_PATH/$repo.tmp_file | awk '{print $1}' >$RESULT_PATH/$repo.packages.list
    sed -i "/^@/d" $RESULT_PATH/$repo.packages.list
}

function gen_installed_list() {
    yum list installed >$RESULT_PATH/installed_tmp_file
    delete_unuse_item $RESULT_PATH/installed_tmp_file
    cat $RESULT_PATH/installed_tmp_file | awk '{print $1}' >$RESULT_PATH/installed.packages.list
}

function chk_bin_file() {
    local pkg_name ret
    pkg_name=$1
    mkdir -p $RESULT_PATH/${pkg_name}
    repoquery -l $pkg_name | grep -E "/bin/|/sbin/" | grep -Ev "/etc/|/libexec/|/opt/" >/dev/null
    ret=$?
    if [ $ret -ne 0 ]; then
        echo "$pkg_name" >>$RESULT_PATH/pkg_do_not_have_bin_file.log
        rm -rf $RESULT_PATH/${pkg_name}
        return 1
    fi
    return 0
}

function service_check() {
    local pkg_name service_flag service_path service_file exist_flag black_list
    local SERVICE_ACTION
    pkg_name=$1
    exist_flag=0
    service_path=$(repoquery -l $pkg_name | grep -E '^/usr/lib/systemd/system/.*.service$' | grep -v @)
    service_flag=$?
    black_list=$(grep $pkg_name $BLACKLIST)
    if [ "$black_list" ]; then
        echo "$pkg_name: SKIP" >>$RESULT_PATH/pkg_service_check_test_result.log
        return 1
    fi 
    
    if [ $service_flag -eq 0 ]; then
        RPM_FLAG=0
        check_pkg_inst $pkg_name
        if inst_pkg $pkg_name; then
            mkdir -p $RESULT_PATH/${pkg_name}
            for path in $service_path; do
                SERVICE_ACTION=("stop" "start" "restart" "status")
				service=$(echo $path | awk -F '/' '{print $NF}')
                grep ExecReload $path && {
                    SERVICE_ACTION=("${SERVICE_ACTION[@]/*reload*/}")
                    SERVICE_ACTION+=("reload")
                }

                for ((i = 0; i < ${#SERVICE_ACTION[@]}; i++)); do
                    timeout -s SIGKILL 10s systemctl ${SERVICE_ACTION[i]} $service --no-pager >> \
                        $RESULT_PATH/${pkg_name}/${service}_${SERVICE_ACTION[i]}.log 2>&1
                    ret=$?
                    if [ "$ret" -ne 0 ]; then
                        ((exist_flag++))
                    else
                        rm -rf $RESULT_PATH/${pkg_name}/${service}_${SERVICE_ACTION[i]}.log
                    fi
                done
            done
            uninst_pkg $pkg_name || {
                echo "$pkg_name: SKIP" >>$RESULT_PATH/pkg_uninstall_failed.log
                return 1
            }
        else
            echo "$pkg_name: SKIP" >>$RESULT_PATH/pkg_install_failed.log
            return 1
        fi
    else
        return 1
    fi

    if [ $exist_flag -ne 0 ]; then
        echo "$pkg_name: FAIL" >>$RESULT_PATH/pkg_service_check_test_result.log
    else
        echo "$pkg_name: PASS" >>$RESULT_PATH/pkg_service_check_test_result.log 
        rm -rf $RESULT_PATH/${pkg_name}
    fi
    return $exist_flag
}

function service_check_by_repo() {
    local repo_id pkg_name
    repo_id=$1
    gen_packages_list $repo_id
    while read line; do
        pkg_name=${line%.$ARCH}
        pkg_name=${pkg_name%.noarch}
        service_check $pkg_name
    done <$RESULT_PATH/$repo_id.packages.list
}

function inst_and_uninst_by_pkg() {
    local inst_flag uninst_flag pkg_name
    pkg_name=$1
    RPM_FLAG=0
    check_pkg_inst $pkg_name
    if echo "$pkg_name" | grep "texlive"; then
        echo "$pkg_name: SKIP" >>$RESULT_PATH/pkg_install_and_uninstall_test_result_by_pkg.log
        return 0
    fi
    inst_pkg $pkg_name
    inst_flag=$?
    uninst_pkg $pkg_name
    uninst_flag=$?
    if [[ $inst_flag == 0 && $uninst_flag == 0 ]]; then
        echo "$pkg_name: PASS" >>$RESULT_PATH/pkg_install_and_uninstall_test_result_by_pkg.log
    else
        echo "$pkg_name: FAIL" >>$RESULT_PATH/pkg_install_and_uninstall_test_result_by_pkg.log
    fi
}

function inst_and_uninst_by_repo() {
    local repo_id
    repo_id=$1
    gen_packages_list $repo_id
    while read line; do
        inst_and_uninst_by_pkg $line
    done <$RESULT_PATH/$repo_id.packages.list
    # if grep "FAIL" $RESULT_PATH/pkg_install_and_uninstall_test_result_by_pkg.log; then
    #     cat $RESULT_PATH/pkg_install_and_uninstall_test_result_by_pkg.log | grep "FAIL" >$RESULT_PATH/pkg_install_and_uninstall_test_result_by_repo.log
    # else
    #     echo "$repo_id: PASS" >$RESULT_PATH/pkg_install_and_uninstall_test_result_by_repo.log
    # fi
}

function exec_bin_file() {
    local cmd pkg_name ret 
    cmd=$1
    pkg_name=$2
    cmd_name=$(echo $cmd | awk -F '/' '{print $NF}')
    if [ -n "$LDDCHECK" ]; then
        ldd_check $cmd
        if [ $? -ne 0 ]; then
            return 2
        fi
    fi
    for ((i = 0; i < ${#HELP_CMD_LIST[@]}; i++)); do
        echo "----------$cmd ${HELP_CMD_LIST[i]} output is: ----------" >>$RESULT_PATH/${pkg_name}/${cmd_name}_exec.log
        timeout -s SIGKILL 10s $cmd ${HELP_CMD_LIST[i]} >>$RESULT_PATH/${pkg_name}/${cmd_name}_exec.log 2>&1 
        ret=$?
        log_size=$(ls -l $RESULT_PATH/${pkg_name}/${cmd_name}_exec.log | awk '{print $5}')
        if [ $log_size -ge $MAX_LOG_SIZE ]; then
            echo "$RESULT_PATH/${pkg_name}/${cmd_name}_exec.log is lagger then 10M" >>$RESULT_PATH/cmd_gen_large_log
            rm -rf $RESULT_PATH/${pkg_name}/${cmd_name}_exec.log
            return 1
        fi
        if [ $ret -ne 0 ]; then
            cat $RESULT_PATH/${pkg_name}/${cmd_name}_exec.log | grep -i "usage\|option"
            if [ $? -ne 0 ]; then
                continue
            else
                rm -rf $RESULT_PATH/${pkg_name}/${cmd_name}_exec.log
                return 0
            fi
        else
            rm -rf $RESULT_PATH/${pkg_name}/${cmd_name}_exec.log
            return 0
        fi
    done
    return 1
}

function exec_pkg_bin_file() {
    local pkg_name ret exist_flag
    pkg_name=$1
    exist_flag=0
    while read -u 8 line; do
        exec_bin_file $line $pkg_name
        ret=$?
        if [ $ret -ne 0 ]; then
            if [ "$ret" == 1 ]; then 
                echo "$line" >>$RESULT_PATH/${pkg_name}/exec_cmd_failed.log
            elif [ "$ret" == 2 ]; then
                echo "$line" >>$RESULT_PATH/${pkg_name}/ldd_cmd_failed.log
            else
                echo "$line" >>$RESULT_PATH/${pkg_name}/unknown_failed.log
            fi
            ((exist_flag++))
        fi
    done 8<$RESULT_PATH/${pkg_name}/chk_bin_file.log
	return $exist_flag
}

function exec_by_pkg() {
    local pkg_name check_core_dump inst_flag uninst_flag exec_flag core_dump_flag
    pkg_name=$1
    check_core_dump=$2
    if chk_bin_file $pkg_name; then
        RPM_FLAG=0
        check_pkg_inst $pkg_name
        if inst_pkg $pkg_name; then
            rpm -ql $pkg_name | grep -E "/bin/|/sbin/" | grep -Ev "/etc/|/libexec/|/opt/" >&$RESULT_PATH/${pkg_name}/chk_bin_file.log
            exec_pkg_bin_file $pkg_name
            exec_flag=$?
            uninst_pkg $pkg_name
            uninst_flag=$?
            if [ $check_core_dump == "check_coredump" ]; then
                check_coredump
                core_dump_flag=$?
                if [ $core_dump_flag -ne 0 ]; then
                    echo "$pkg_name" >>$RESULT_PATH/pkg_gen_coredump.log
                    echo "$pkg_name: FAIL" >>$RESULT_PATH/pkg_help_test_result.log
                    return 1
                fi
            fi
            if [ $exec_flag -eq 0 ]; then
                echo "$pkg_name: PASS" >>$RESULT_PATH/pkg_help_test_result.log
                rm -rf $RESULT_PATH/${pkg_name}
                return 0
            else
                echo "$pkg_name: FAIL" >>$RESULT_PATH/pkg_help_test_result.log
                return 1
            fi
        else
            echo "$pkg_name: SKIP" >>$RESULT_PATH/pkg_help_test_result.log
            rm -rf $RESULT_PATH/${pkg_name}
            return 1
        fi
    fi
}

function exec_by_repo() {
    local repo_id check_core_dump
    repo_id=$1
    check_core_dump=$2
    gen_packages_list $repo_id
    while read -u 9 line; do
        exec_by_pkg $line $check_core_dump
    done 9<$RESULT_PATH/$repo_id.packages.list
}
